use crate::protocol::{RedisCommand, RespValue};
use crate::storage::{Storage, StorageEngine, RedisValue};
use std::collections::HashSet;

/// LPUSH key element [element ...]
pub async fn lpush(storage: &Storage, command: RedisCommand) -> RespValue {
    if command.arg_count() < 2 {
        return RespValue::error("ERR wrong number of arguments for 'lpush' command");
    }

    let key = &command.args[0];
    let elements = &command.args[1..];

    // Get existing list or create new one
    let mut list = match storage.get(key) {
        Some(RedisValue::List(existing_list)) => existing_list,
        Some(_) => return RespValue::error("WRONGTYPE Operation against a key holding the wrong kind of value"),
        None => Vec::new(),
    };

    // Add elements to the left (beginning) of the list
    for element in elements.iter().rev() {
        list.insert(0, element.clone());
    }

    let new_length = list.len();
    storage.set(key.clone(), RedisValue::List(list), None);
    RespValue::integer(new_length as i64)
}

/// RPUSH key element [element ...]
pub async fn rpush(storage: &Storage, command: RedisCommand) -> RespValue {
    if command.arg_count() < 2 {
        return RespValue::error("ERR wrong number of arguments for 'rpush' command");
    }

    let key = &command.args[0];
    let elements = &command.args[1..];

    // Get existing list or create new one
    let mut list = match storage.get(key) {
        Some(RedisValue::List(existing_list)) => existing_list,
        Some(_) => return RespValue::error("WRONGTYPE Operation against a key holding the wrong kind of value"),
        None => Vec::new(),
    };

    // Add elements to the right (end) of the list
    for element in elements {
        list.push(element.clone());
    }

    let new_length = list.len();
    storage.set(key.clone(), RedisValue::List(list), None);
    RespValue::integer(new_length as i64)
}

/// LPOP key
pub async fn lpop(storage: &Storage, command: RedisCommand) -> RespValue {
    if command.arg_count() != 1 {
        return RespValue::error("ERR wrong number of arguments for 'lpop' command");
    }

    let key = &command.args[0];

    match storage.get(key) {
        Some(RedisValue::List(mut list)) => {
            if list.is_empty() {
                RespValue::null_bulk_string()
            } else {
                let element = list.remove(0);
                if list.is_empty() {
                    storage.del(key);
                } else {
                    storage.set(key.clone(), RedisValue::List(list), None);
                }
                RespValue::bulk_string(element)
            }
        }
        Some(_) => RespValue::error("WRONGTYPE Operation against a key holding the wrong kind of value"),
        None => RespValue::null_bulk_string(),
    }
}

/// RPOP key
pub async fn rpop(storage: &Storage, command: RedisCommand) -> RespValue {
    if command.arg_count() != 1 {
        return RespValue::error("ERR wrong number of arguments for 'rpop' command");
    }

    let key = &command.args[0];

    match storage.get(key) {
        Some(RedisValue::List(mut list)) => {
            if list.is_empty() {
                RespValue::null_bulk_string()
            } else {
                let element = list.pop().unwrap();
                if list.is_empty() {
                    storage.del(key);
                } else {
                    storage.set(key.clone(), RedisValue::List(list), None);
                }
                RespValue::bulk_string(element)
            }
        }
        Some(_) => RespValue::error("WRONGTYPE Operation against a key holding the wrong kind of value"),
        None => RespValue::null_bulk_string(),
    }
}

/// LLEN key
pub async fn llen(storage: &Storage, command: RedisCommand) -> RespValue {
    if command.arg_count() != 1 {
        return RespValue::error("ERR wrong number of arguments for 'llen' command");
    }

    let key = &command.args[0];

    match storage.get(key) {
        Some(RedisValue::List(list)) => RespValue::integer(list.len() as i64),
        Some(_) => RespValue::error("WRONGTYPE Operation against a key holding the wrong kind of value"),
        None => RespValue::integer(0),
    }
}

/// LRANGE key start stop
pub async fn lrange(storage: &Storage, command: RedisCommand) -> RespValue {
    if command.arg_count() != 3 {
        return RespValue::error("ERR wrong number of arguments for 'lrange' command");
    }

    let key = &command.args[0];
    let start = match command.args[1].parse::<i64>() {
        Ok(s) => s,
        Err(_) => return RespValue::error("ERR value is not an integer or out of range"),
    };
    let stop = match command.args[2].parse::<i64>() {
        Ok(s) => s,
        Err(_) => return RespValue::error("ERR value is not an integer or out of range"),
    };

    match storage.get(key) {
        Some(RedisValue::List(list)) => {
            let len = list.len() as i64;

            // Handle negative indices
            let start_idx = if start < 0 { (len + start).max(0) } else { start.min(len) } as usize;
            let stop_idx = if stop < 0 { (len + stop + 1).max(0) } else { (stop + 1).min(len) } as usize;

            if start_idx >= stop_idx {
                return RespValue::array(vec![]);
            }

            let slice = &list[start_idx..stop_idx];
            let result: Vec<RespValue> = slice.iter()
                .map(|s| RespValue::bulk_string(s.clone()))
                .collect();

            RespValue::array(result)
        }
        Some(_) => RespValue::error("WRONGTYPE Operation against a key holding the wrong kind of value"),
        None => RespValue::array(vec![]),
    }
}